# app/dao/expense_first_cate_dao.py
from app.db import db  # 从独立的 db 模块导入
from app.Models.FinanceModels.ExpenseFirstCate import ExpenseFirstCate  # 按实际模型路径调整
from sqlalchemy.exc import IntegrityError  # 用于捕获唯一性约束异常


class ExpenseFirstCateDAO:
    """支出一级分类模型的数据访问对象"""

    @staticmethod
    def create_first_cate(first_cate_name):
        """
        新增支出一级分类
        :param first_cate_name: 一级分类名称（如"餐饮美食"、"交通出行"）
        :return: 新增的一级分类对象
        :raises ValueError: 分类名称为空或已存在时抛出
        """
        # 1. 基础校验：分类名称不能为空
        if not first_cate_name or first_cate_name.strip() == "":
            raise ValueError("支出一级分类名称不能为空")

        # 2. 避免重复：先查询名称是否已存在（也可依赖数据库唯一约束，这里双重保障）
        existing_cate = ExpenseFirstCateDAO.get_first_cate_by_name(first_cate_name)
        if existing_cate:
            raise ValueError(f"支出一级分类名称已存在：{first_cate_name}")

        # 3. 新增分类并提交
        try:
            new_cate = ExpenseFirstCate(
                first_cate_name=first_cate_name.strip()  # 去除首尾空格，避免无效重复
            )
            db.session.add(new_cate)
            db.session.commit()
            return new_cate
        except IntegrityError:
            # 若数据库表设置了 first_cate_name 唯一约束，捕获未提前校验的重复异常
            db.session.rollback()  # 回滚事务，避免影响后续操作
            raise ValueError(f"支出一级分类名称已存在：{first_cate_name}")

    @staticmethod
    def get_first_cate_by_id(cate_id):
        """
        根据ID查询支出一级分类
        :param cate_id: 一级分类ID
        :return: 一级分类对象（存在则返回，不存在返回None）
        """
        return ExpenseFirstCate.query.get(cate_id)

    @staticmethod
    def get_first_cate_by_name(cate_name):
        """
        根据名称查询支出一级分类（用于唯一性校验、精准查询）
        :param cate_name: 一级分类名称
        :return: 一级分类对象（存在则返回，不存在返回None）
        """
        if not cate_name:
            return None
        return ExpenseFirstCate.query.filter_by(
            first_cate_name=cate_name.strip()
        ).first()

    @staticmethod
    def get_all_first_cates():
        """
        查询所有支出一级分类（按ID升序排列，保证分类顺序稳定）
        :return: 一级分类列表（空列表表示无数据）
        """
        return ExpenseFirstCate.query.order_by(ExpenseFirstCate.id.asc()).all()

    @staticmethod
    def update_first_cate(cate_id, new_name):
        """
        更新支出一级分类名称
        :param cate_id: 待更新的一级分类ID
        :param new_name: 新的分类名称
        :return: 更新后的一级分类对象
        :raises ValueError: 分类不存在、名称为空或新名称已存在时抛出
        """
        # 1. 校验分类是否存在
        cate = ExpenseFirstCateDAO.get_first_cate_by_id(cate_id)
        if not cate:
            raise ValueError(f"支出一级分类不存在（ID：{cate_id}）")

        # 2. 校验新名称合法性
        new_name = new_name.strip() if new_name else ""
        if not new_name:
            raise ValueError("支出一级分类名称不能为空")

        # 3. 校验新名称是否与其他分类重复（排除自身）
        existing_cate = ExpenseFirstCateDAO.get_first_cate_by_name(new_name)
        if existing_cate and existing_cate.id != cate_id:
            raise ValueError(f"支出一级分类名称已存在：{new_name}")

        # 4. 执行更新并提交
        try:
            cate.first_cate_name = new_name
            db.session.commit()
            return cate
        except IntegrityError:
            db.session.rollback()
            raise ValueError(f"更新失败：支出一级分类名称已存在（{new_name}）")

    @staticmethod
    def delete_first_cate(cate_id, check_relation=False, related_dao=None):
        """
        删除支出一级分类（支持关联校验，避免删除被引用的分类）
        :param cate_id: 待删除的一级分类ID
        :param check_relation: 是否校验分类是否被二级分类引用（True/False）
        :param related_dao: 关联的二级分类DAO（如 ExpenseSecondCateDAO，check_relation=True时必填）
        :return: True（删除成功）
        :raises ValueError: 分类不存在或被引用时抛出
        """
        # 1. 校验分类是否存在
        cate = ExpenseFirstCateDAO.get_first_cate_by_id(cate_id)
        if not cate:
            raise ValueError(f"支出一级分类不存在（ID：{cate_id}）")

        # 2. 可选：校验分类是否被二级分类引用（避免数据关联错误）
        if check_relation:
            if not related_dao:
                raise ValueError("校验关联关系时，需传入 related_dao（如 ExpenseSecondCateDAO）")
            # 调用二级分类DAO查询是否有引用该一级分类的记录
            related_seconds = related_dao.get_seconds_by_first_cate(cate_id)
            if related_seconds:
                raise ValueError(
                    f"无法删除：该一级分类下存在{len(related_seconds)}个二级分类（ID：{cate_id}）"
                )

        # 3. 执行删除并提交
        try:
            db.session.delete(cate)
            db.session.commit()
            return True
        except Exception as e:
            db.session.rollback()
            raise ValueError(f"删除支出一级分类失败：{str(e)}")